////////////////////////////////////////////////////////////////////////////////
/// @file    uartx.c
/// @author  AE TEAM
/// @brief   Output received data.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////
// Define to prevent recursive inclusion
#define _UARTX_C_

// Files includes
#include "delay.h"
#include "uartx.h"

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Hardware_Abstract_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup UARTX
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup UARTX_Exported_Functions
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @brief  Get UART index
/// @param  UARTx
/// @retval UART index value
////////////////////////////////////////////////////////////////////////////////
u8 Get_UART_Index(UART_TypeDef* UARTx)
{
    if      (UARTx == UART1)    return 0;
    else if (UARTx == UART2)    return 1;
    return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Setup this IP clock
/// @note   This function should affected by chip version.
/// @param  UARTx : Select UART port.
/// @param  NewState : Enable or disable the IP clock.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void CFG_UART_Clock(UART_TypeDef* UARTx, FunctionalState NewState)
{
    if      (UARTx == UART1) {

        RCC_APB1PeriphClockCmd(RCC_APB1ENR_UART1, NewState);
    }
    else if (UARTx == UART2) {
        //CFG_IpClock(emIPCLOCK_UART2, NewState);
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_UART2, NewState);
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  UART1 Pin Config
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
s32 UART1PinConfigWithParameter(void)
{
    s32 result = 0;
    //customer can change below config based Pin assign
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_StructInit(&GPIO_InitStructure);
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_1);
    //UART1_TX   GPIOA.12
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //UART1_RX    GPIOA.0
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Serial port initialization configuration
/// @note
/// @param  bound: Baud rate
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void UART1InitWithParameter(u32 bound)
{
    UART_InitTypeDef UART_InitStructure;

    UART_StructInit(&UART_InitStructure);

    CFG_UART_Clock(UART1, ENABLE);
    //set as 8-N-1 Customer can change below parameters
    UART_InitStructure.BaudRate       = bound;
    UART_InitStructure.WordLength     = UART_WordLength_8b;
    UART_InitStructure.StopBits       = UART_StopBits_1;
    UART_InitStructure.Parity         = UART_Parity_No;
    UART_InitStructure.Mode           = UART_Mode_Rx | UART_Mode_Tx;
    UART_InitStructure.HWFlowControl  = UART_HWFlowControl_None;

    UART_Init(UART1, &UART_InitStructure);
    UART_Cmd(UART1, ENABLE);
}


////////////////////////////////////////////////////////////////////////////////
/// @brief  NVIC Configure, Applicable to Cortex M0 or M3 processors.
/// @param  NVIC Channel, Priority or SubPriority.
/// @arg    ch: IRQChannel
/// @arg    pri: Priority, Use only Cortex-M3
/// @arg    sub: SubPriority
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
static void NVIC_Configure(u8 ch, u8 pri, u8 sub)
{

    exNVIC_Init_TypeDef  NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = ch;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = pri;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = sub;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    exNVIC_Init(&NVIC_InitStruct);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief
/// @param
/// @retval UART IRQ index
////////////////////////////////////////////////////////////////////////////////
static u8 Get_UART_IRQ_Flag(UART_TypeDef* UARTn)
{
    if(UARTn == UART1)      return UART1_IRQn;
    else if(UARTn == UART2) return UART2_IRQn;

    return UART1_IRQn;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Serial Port Nvic initialization
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void UARTxNvicInit(UART_TypeDef* UARTx, u8 pri, u8 sub)
{
    NVIC_Configure(Get_UART_IRQ_Flag(UARTx), pri, sub);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  UART1 Nvic initialization
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void UART1NvicInitWithParameter(void)
{
    UARTxNvicInit(UART1, 2, 0);
}


typedef  struct UART_SendItStruct {
    u32  UartSendBufferAddress;
    u32  UartSendLen;
    u32  UartSendRealCnt;
    bool UartSendComplete;
} UART_SendIt_Typedef;
typedef  struct UART_RecvItStruct {
    u32  UartRecvBufferAddress;
    u32  UartRecvLen;
    u32  UartRecvRealCnt;
    bool UartRecvComplete;
} UART_RecvIt_Typedef;
UART_SendIt_Typedef UART1SendStruct;
UART_RecvIt_Typedef UART1RecvStruct;

#define RECVBUFLENGTH 100
__IO s8 sSendBuf[RECVBUFLENGTH] = "0123456789ABCDEFGHIJKLMN";
__IO u8 sRecvBuf[RECVBUFLENGTH];

__IO u16 RecvLen;
__IO u16 sSendLen;
////////////////////////////////////////////////////////////////////////////////
/// @brief  UART send byte.
/// @note   None.
/// @param  buf:buffer address.
/// @param  len:data length.
/// @retval s32  -1 = Failure, 0 successful.
////////////////////////////////////////////////////////////////////////////////
s32 UART1_SendPacketInterrupt(u8* buf, u16 len)
{
    UART_TypeDef* UARTx;
    UART_SendIt_Typedef* pUARTxSendStruct;
    UARTx = UART1;
    pUARTxSendStruct = &UART1SendStruct;
    UART_ITConfig(UARTx, UART_IT_TXIEN, DISABLE);
    if(len == 0) {
        return -1;
    }
    else if(len == 1) {
        UART_SendData(UARTx, *((u8*)(buf)));
    }
    else {
        pUARTxSendStruct->UartSendComplete = false;
        pUARTxSendStruct->UartSendBufferAddress = (u32)(buf);
        pUARTxSendStruct->UartSendLen = (u32)(len);
        pUARTxSendStruct->UartSendRealCnt = 0;
        UART_ITConfig(UARTx, UART_IT_TXIEN, ENABLE);
    }
    return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Serial port Interrupt checking Sending Finish
/// @note
/// @param  None
/// @retval s32  -1 = Failure, 0 successful..
////////////////////////////////////////////////////////////////////////////////
s32 UART1_CheckItSendingFinish(void)
{
    s32 temp;
    if(UART1SendStruct.UartSendComplete == 1) {
        UART1SendStruct.UartSendComplete = 0;
        temp = UART1SendStruct.UartSendRealCnt;
        UART1SendStruct.UartSendRealCnt = 0;
        return temp;
    }
    else {
        return -1;
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  UART Recv byte.
/// @note   None.
/// @param  buf:buffer address.
/// @param  len:data length.
/// @retval s32  -1 = Failure, 0 successful.
////////////////////////////////////////////////////////////////////////////////
s32 UART1_RecvPacketInterrupt(u8* buf, u16 len)
{
    UART_RecvIt_Typedef* pUARTxRecvStruct;

    pUARTxRecvStruct = &UART1RecvStruct;

    if(len == 0) {
        return -1;
    }
    else {
        pUARTxRecvStruct->UartRecvComplete = false;
        pUARTxRecvStruct->UartRecvBufferAddress = (u32)(buf);
        pUARTxRecvStruct->UartRecvLen = (u32)(len);
        pUARTxRecvStruct->UartRecvRealCnt = 0;
    }
    return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Serial port Interrupt checking Recving Finish
/// @note
/// @param  None
/// @retval s32  -1 = Failure, 0 successful..
////////////////////////////////////////////////////////////////////////////////
s32 UART1_CheckItReceiveFinish(void)
{
    s32 temp;
    if(UART1RecvStruct.UartRecvComplete == 1) {
        UART1RecvStruct.UartRecvComplete = 0;
        temp = UART1RecvStruct.UartRecvRealCnt;
        UART1RecvStruct.UartRecvRealCnt = 0;
        return temp;
    }
    else {
        return -1;
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Serial port Interrupt Handler
/// @note
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void UART1_IRQHandler(void)
{
    u8 recvbyte;
    UART_TypeDef* UARTx;
    UART_SendIt_Typedef* pUARTxSendStruct;
    UART_RecvIt_Typedef* pUARTxRecvStruct;
    UARTx = UART1;
    pUARTxSendStruct = &UART1SendStruct;
    pUARTxRecvStruct = &UART1RecvStruct;
    // Send packet
    if (UART_GetITStatus(UARTx, UART_IT_TXIEN) != RESET) {
        UART_ClearITPendingBit(UARTx, UART_IT_TXIEN);
        if(pUARTxSendStruct->UartSendComplete == false) {
            if( pUARTxSendStruct->UartSendLen <= pUARTxSendStruct->UartSendRealCnt) {
                pUARTxSendStruct->UartSendLen = 0;
                UART_ITConfig(UARTx, UART_IT_TXIEN, DISABLE);
                while (!UART_GetFlagStatus(UARTx, UART_CSR_TXC));
                pUARTxSendStruct->UartSendComplete = true;
            }
            else {
                if(pUARTxSendStruct->UartSendRealCnt < RECVBUFLENGTH) {
                    UART_SendData(UARTx, *(u8*)(pUARTxSendStruct->UartSendBufferAddress + pUARTxSendStruct->UartSendRealCnt));
                    pUARTxSendStruct->UartSendRealCnt++;
                }
            }
        }
    }
    // Recv packet
    if (UART_GetITStatus(UARTx, UART_ISR_RX) != RESET) {
        UART_ClearITPendingBit(UARTx, UART_ISR_RX);
        recvbyte = UART_ReceiveData(UARTx);
        if(pUARTxRecvStruct->UartRecvComplete == false) {
            if(pUARTxRecvStruct->UartRecvRealCnt < RECVBUFLENGTH) {
                *(u8*)(pUARTxRecvStruct->UartRecvBufferAddress + pUARTxRecvStruct->UartRecvRealCnt) = recvbyte;
                pUARTxRecvStruct->UartRecvRealCnt++;
                if( pUARTxRecvStruct->UartRecvLen == pUARTxRecvStruct->UartRecvRealCnt) {
                    pUARTxRecvStruct->UartRecvLen = 0;
                    pUARTxRecvStruct->UartRecvComplete = true;
                }
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Run Tx Rx interrupt test
/// @note
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void UART1RxTxTransceiving(void)
{
    s32 result;
    u16 realrecvLen = 0;
    RecvLen = 10;
    UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);
    //UART_ITConfig(UART1, UART_IT_TXIEN, ENABLE);
    while(1) {
        UART1_RecvPacketInterrupt((u8*)&sRecvBuf[0], RecvLen);
        while(1) {
            result = UART1_CheckItReceiveFinish();
            if(result > 0) {
                realrecvLen = (u16)(result & 0xFFFF);
                break;
            }
        }
        sSendLen = realrecvLen;
        memcpy((u8*)&sSendBuf[0], (u8*)&sRecvBuf[0], sSendLen);
        UART1_SendPacketInterrupt((u8*)&sSendBuf[0], sSendLen);
        while(1) {
            if(sSendLen == UART1_CheckItSendingFinish()) {
                break;
            }
        }
    }
    //return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Serial port initialization configuration
/// @note    It must be careful of the Chip Version.
/// @param  bound: Baud rate
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void UART1_NVIC_Init(u32 bound)
{
    UART1PinConfigWithParameter();
    UART1InitWithParameter(bound);
    UART1NvicInitWithParameter();
}

/// @}


/// @}

/// @}


